﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace Elca.MvvmHelpers {

    public class DoubleClickHelper {

        private static readonly List<FrameworkElement> s_knownElements = new List<FrameworkElement>();

        public static ICommand GetCommand(DependencyObject d) {
            return (ICommand) d.GetValue(CommandProperty);
        }

        public static void SetCommand(DependencyObject d, ICommand value) {
            d.SetValue(CommandProperty, value);
        }

        public static readonly DependencyProperty CommandProperty =
            DependencyProperty.RegisterAttached("Command", 
                                                typeof(ICommand), 
                                                typeof(DoubleClickHelper),
                                                new FrameworkPropertyMetadata(CommandChanged));

        public static void CommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {

            var ctl = d as Control;
            if (ctl == null) {
                throw new Exception("Command attached property only works on a Control type");
            }

            RememberElement(ctl);
        }

        private static void RememberElement(Control ctl) {

            if (! s_knownElements.Contains(ctl)) {
                s_knownElements.Add(ctl);

                RegisterEvents(ctl);
            } 
            // nothing to do if elt is known
        }

        private static void OnUnloaded(object sender, RoutedEventArgs e) {

            Control ctl = (Control) sender;
            ForgetControl(ctl);
        }

        private static void ForgetControl(Control ctl) {

            s_knownElements.Remove(ctl);
            UnregisterEvents(ctl);
        }

        private static void RegisterEvents(Control ctl) {
            ctl.Unloaded += OnUnloaded;
            ctl.MouseDoubleClick += OnDoubleClick;
        }

        private static void UnregisterEvents(Control rb) {
            rb.Unloaded -= OnUnloaded;
            rb.MouseDoubleClick -= OnDoubleClick;
        }

        private static void OnDoubleClick(object sender, MouseButtonEventArgs e) {

            Control ctl = (Control) sender;
            ICommand cmd = GetCommand(ctl);
            if (cmd != null && cmd.CanExecute(null)) {
                cmd.Execute(null);
            }
        }
    }
}
